package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.FormDataValidateProductHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.TransactionHelp;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.pojo.AssociatedBusinessAfterSavePojo;
import com.xbongbong.paas.pojo.ButtonPojo;
import com.xbongbong.paas.pojo.WorkFlowPojo;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.ProcessNodeTaskUpdateDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.FormDataGetVO;
import com.xbongbong.paas.service.CouponService;
import com.xbongbong.paas.service.PaasAppService;
import com.xbongbong.parent.interfaces.DynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.service.team.TeamDataHelp;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.businessproduct.pojo.dto.BusinessProductListDTO;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.contractperformance.pojo.dto.ContractPerformanceDeleteBatchDTO;
import com.xbongbong.pro.contractproduct.pojo.dto.ContractProductDeleteBatchDTO;
import com.xbongbong.pro.contractproduct.pojo.dto.ContractProductListDTO;
import com.xbongbong.pro.contractproduct.pojo.vo.ContractProductListVO;
import com.xbongbong.pro.customercommunicate.pojo.dto.CustomerDynamicAddDTO;
import com.xbongbong.pro.detailtab.dto.ChangeDocumentStatusSaveDTO;
import com.xbongbong.pro.detailtab.vo.ChangeDocumentStatusSaveVO;
import com.xbongbong.pro.detailtab.vo.ProductSummaryVO;
import com.xbongbong.pro.domain.entity.ReRollBackEntity;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.RefundStatusEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.ContractErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.RefundErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.message.constant.DistributorOrderPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.DistributorMessageRabbitMqDTO;
import com.xbongbong.pro.product.pojo.dto.FilterAttrOnOffJXCDTO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.refund.pojo.dto.RefundUpdateBatchDTO;
import com.xbongbong.pro.refund.pojo.dto.RefundUpdateDTO;
import com.xbongbong.pro.refund.pojo.vo.RefundRedContractVO;
import com.xbongbong.pro.refunduser.pojo.dto.RefundUserDeleteBatchDTO;
import com.xbongbong.pro.returned.pojo.dto.ReturnDeleteBatchDTO;
import com.xbongbong.pro.returned.pojo.dto.ReturnEditAttrUpdateDTO;
import com.xbongbong.pro.returned.pojo.vo.ReturnDeleteBatchVO;
import com.xbongbong.pro.returned.pojo.vo.ReturnEditAttrUpdateVO;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.RefundEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperatePageEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.business.RefundInstockEnum;
import com.xbongbong.saas.enums.business.ReturnEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryEnum;
import com.xbongbong.saas.enums.dictionary.EnableButtonEnum;
import com.xbongbong.saas.enums.dictionary.ReturnStatusEnum;
import com.xbongbong.saas.enums.dictionary.ReturnTypeEnum;
import com.xbongbong.saas.enums.product.ContractProductEnum;
import com.xbongbong.saas.enums.subform.ContractProductSubFormEnum;
import com.xbongbong.saas.help.DefaultAttrHelp;
import com.xbongbong.saas.help.ExplainHelp;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.ProDetailHandlerHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.DataDictionaryModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.RefundInvoiceModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.service.ContractPerformanceService;
import com.xbongbong.saas.service.ContractProductService;
import com.xbongbong.saas.service.ContractService;
import com.xbongbong.saas.service.CustomerCommunicateService;
import com.xbongbong.saas.service.MobileDetailService;
import com.xbongbong.saas.service.ProductSerialService;
import com.xbongbong.saas.service.RefundService;
import com.xbongbong.saas.service.RefundUserService;
import com.xbongbong.saas.service.ReturnService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;


@Service("returnService")
public class ReturnServiceImpl implements ReturnService {

    private static final Logger LOG = LoggerFactory.getLogger(ReturnServiceImpl.class);
    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private ExplainHelp explainHelp;
    @Resource
    private DefaultAttrHelp defaultAttrHelp;
    @Resource
    private ContractModel contractModel;
    @Resource
    private FormDataValidateProductHelp formDataValidateProductHelp;
    @Resource
    private PaasAppService paasAppService;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private RefundModel refundModel;
    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private UserModel userModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    @Lazy
    private CustomerCommunicateService customerCommunicateService;
    @Resource
    private DataDictionaryModel dataDictionaryModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private RefundServiceImpl refundServiceImpl;
    @Resource
    private RefundService refundService;
    @Resource
    private LogHelp logHelp;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private ContractService contractService;
    @Resource
    private ProductSerialService productSerialService;
    @Resource
    private EsHelper esHelper;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private RefundUserService refundUserService;
    @Resource
    private RefundInvoiceModel refundInvoiceModel;
    @Resource
    private ContractPerformanceService contractPerformanceService;
    @Resource
    private ContractProductService contractProductService;
    @Resource
    private MobileDetailService mobileDetailService;
    @Resource
    private ProDetailHandlerHelp proDetailHandlerHelp;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private CouponService couponService;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private TeamDataHelp teamDataHelp;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private TransactionHelp transactionHelp;

    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        JSONObject data = validateDataDTO.getData();
        String corpid = validateDataDTO.getCorpid();
        String serialNo = validateDataDTO.getSerialNo();
        Long returnId = validateDataDTO.getDataId();
        TaskTypeEnum taskTypeEnum = validateDataDTO.getTaskTypeEnum();
        boolean isNew = (returnId == null || Objects.equals(returnId, 0L));
        saasSaveHelp.formatLinkBusiness4Save(data, ReturnEnum.LINK_DISTRIBUTOR.getAttr(), ReturnEnum.LINK_DISTRIBUTOR_LINKED_TEXT.getAttr(), ReturnEnum.LINK_DISTRIBUTOR_LINKED_TEXT.getFieldType());
        saasSaveHelp.formatLinkBusiness4Save(data, ReturnEnum.ORDER_ID.getAttr(), ReturnEnum.ORDER_ID_LINKED_TEXT.getAttr(), ReturnEnum.ORDER_ID_LINKED_TEXT.getFieldType());

        //序列号必填校验
        saasSaveHelp.batchSaveRequiredCheck(validateDataDTO);
//        saasSaveHelp.formatLinkBusiness4Save(data, ReturnEnum.PAYMENT_SHEETS.getAttr(), ReturnEnum.PAYMENT_SHEETS_LINKED_TEXT.getAttr(), ReturnEnum.PAYMENT_SHEETS.getFieldType());
//        saasSaveHelp.formatLinkBusiness4Save(data, ReturnEnum.INVOICES.getAttr(), ReturnEnum.INVOICES_LINKED_TEXT.getAttr(), ReturnEnum.INVOICES.getFieldType());
        Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CONTRACT_ID.getAttr(), 0L);
        ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
        if (Objects.isNull(contractEntityExt)) {
            throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
        }
        if (Objects.isNull(contractEntityExt.getData())) {
            throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
        }
        if (isNew){
            for (Map.Entry<String, Object> entry : SaasDataInitHelp.initReturn(validateDataDTO.getLoginUserName()).entrySet()) {
                SaasDataInitHelp.antDataSet(data,entry.getKey(),entry.getValue());
            }
        }else if (Objects.equals(TaskTypeEnum.COMMIT,taskTypeEnum)){
            // 编辑进审批通过后更新退货单状态 没产品的状态直接更新为已完成
            JSONArray productJsonArray = validateDataDTO.getData().getJSONArray(RefundEnum.PRODUCTS.getAttr());
            if(Objects.nonNull(productJsonArray) && productJsonArray.size() > 0){
                data.put(ReturnEnum.ORDER_STATUS.getAttr(),ReturnStatusEnum.PROCESSING.getCode());
                couponService.returnCoupon(contractEntityExt, data, corpid);
            }else {
                data.put(ReturnEnum.ORDER_STATUS.getAttr(),ReturnStatusEnum.COMPLETED.getCode());
            }
        }
        JSONArray productArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,RefundEnum.PRODUCTS.getAttr(),new JSONArray());
        // jxc开启时:查询退货出库产品  jxc关闭时:查询退货合同产品
        Long refundId = validateDataDTO.getDataId();
        validateDataProduct(productArray, corpid, contractId, refundId);
        Double returnAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);
        if (returnAmount == 0 && productArray.size() == 0) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215024);
        }
        Double refundAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.REFUND_AMOUNT.getAttr(), 0D);
        // 经销商端仅退货时金额校验特殊处理 --> refundMethod
        refundAmountJudgement(corpid, refundAmount, returnAmount, contractId, 0L,serialNo);
        validateDataDTO.setData(data);
    }

    @Override
    public void afterSave(SaasFormSaveDTO saasFormSaveDTO, AssociatedBusinessAfterSavePojo associatedBusinessAfterSavePojo) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();

        RefundEntityExt newRefundEntityExt = new RefundEntityExt();
        BeanUtil.copyProperties(newPaasFormDataEntity, newRefundEntityExt);

        JSONObject newData = saasFormSaveDTO.getNewData();
        String corpid = saasFormSaveDTO.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();
        // todo 审批
        Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(newData, RefundEnum.CUSTOMER_ID.getAttr(), 0L);

        Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(newData, RefundEnum.CONTRACT_ID.getAttr(), 0L);

        Double returnAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(newData, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);

        ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
        if (isNew) {
            //ContractEntityExt redContractEntity = generateRedContract(newPaasFormDataEntity, contractEntityExt, returnAmount, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getProductArray(), FlowStatusEnum.NOT_NEED_APPROVAL.getType());
            //JSONArray invoiceIdArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, RefundEnum.INVOICES.getAttr(), jsonArray);
            RefundRedContractVO refundRedContractVO = refundServiceImpl.generateRedContract(newPaasFormDataEntity, contractEntityExt, returnAmount, saasFormSaveDTO.getNewData().getJSONArray(RefundEnum.PRODUCTS.getAttr()), FlowStatusEnum.NOT_NEED_APPROVAL.getType(), saasFormSaveDTO.getIsNew(), saasFormSaveDTO.getLoginUser());
            ContractEntityExt redContractEntity = refundRedContractVO.getContractEntityExt();
            Long redContractId = redContractEntity.getId();
            //TODO 新建关联回款单和发票做异步处理，新建红冲合同步骤也可以走异步，业务逻辑需要开发负责人确认
//            Runnable runnable = () -> {
//                try {
            ReRollBackEntity reRollBackEntity = associatedBusinessAfterSavePojo.getReRollBackEntity();
            List<Long> redPaymentSheetIds = refundServiceImpl.generateRedPayment(redContractEntity, associatedBusinessAfterSavePojo.getSheetArray(), saasFormSaveDTO);
            reRollBackEntity.setRedSheetId(redPaymentSheetIds);
            List<Long> redPaymentIds = refundServiceImpl.generateRedPaymentPlan(redContractEntity, associatedBusinessAfterSavePojo.getPaymentArray(), saasFormSaveDTO);
            reRollBackEntity.setRedPaymentId(redPaymentIds);
            // --关联发票红冲/作废--*/
            List<Long> invoiceIds = refundServiceImpl.saveRefundInvoice(saasFormSaveDTO, associatedBusinessAfterSavePojo.getInvoiceArray(), redContractId, FlowStatusEnum.NOT_NEED_APPROVAL.getType());
            reRollBackEntity.setRedInvoiceId(invoiceIds);
            JSONObject refundData = newPaasFormDataEntity.getData();
            // 更新退货退款中关联发票和关联红冲回款单字段内容（红冲发票和红冲回款单属于新建，其id在新建成功后才能拿到）
            if (!invoiceIds.isEmpty()) {
                refundData.put(RefundEnum.INVOICES.getAttr(), invoiceIds);
            } else {
                refundData.put(RefundEnum.INVOICES.getAttr(), null);
                refundData.put(RefundEnum.INVOICES_LINKED_TEXT.getAttr(), null);
            }
            if (!redPaymentSheetIds.isEmpty()) {
                refundData.put(RefundEnum.PAYMENT_SHEETS.getAttr(), redPaymentSheetIds);
                if (associatedBusinessAfterSavePojo.getRefundAmount() != null) {
                    refundData.put(RefundEnum.REFUND_AMOUNT.getAttr(), associatedBusinessAfterSavePojo.getRefundAmount());
                }
            } else {
                refundData.put(RefundEnum.PAYMENT_SHEETS.getAttr(), null);
                refundData.put(RefundEnum.PAYMENT_SHEETS_LINKED_TEXT.getAttr(), null);
            }
            //应收款无审批
            if (!redPaymentIds.isEmpty()) {
                refundData.put(RefundEnum.PAYMENTS.getAttr(), redPaymentIds);
            } else {
                refundData.put(RefundEnum.PAYMENTS.getAttr(), null);
                refundData.put(RefundEnum.PAYMENTS_LINKED_TEXT.getAttr(), null);
            }
            newPaasFormDataEntity.setData(refundData);
            RefundEntityExt refundEntityExt = new RefundEntityExt();
            BeanUtils.copyProperties(newPaasFormDataEntity, refundEntityExt);
            // TODO: 2020/11/4 不更新子表单
            refundModel.save(refundEntityExt, false);
            // 项目日志
            String creatorId = newPaasFormDataEntity.getCreatorId();
            UserEntity creatorUser = userModel.getByKey(creatorId, corpid);

            // 动态
            try {
                if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                    String customerName = FastJsonHelper.getStringOrDefaultFromFormData(newData, RefundEnum.CUSTOMER_ID_LINKED_TEXT.getAttr(), "");
                    String refundReason = FastJsonHelper.getStringFromFormData(newData, RefundEnum.REFUND_REASON.getAttr());
                    String communicateMemo = creatorUser.getName() + I18nMessageUtil.getMessage(I18nStringConstant.CREATE_REFUND);
                    if (!StringUtil.isEmpty(refundReason)) {
                        //获取启用的退货原因
                        Map<String, String> refundReasonMap = dataDictionaryModel.getDictionaryMap4Saas(DictionaryEnum.REFUND_REASON, corpid, newPaasFormDataEntity.getFormId());
                        String refundReasonStr = refundReasonMap.get(refundReason) == null ? "" : refundReasonMap.get(refundReason);
                        if (!StringUtil.isEmpty(refundReasonStr)) {
                            communicateMemo += "，" + RefundEnum.REFUND_REASON.getAttrName() + ": " + refundReasonStr;
                        }
                    }
                    CustomerDynamicAddDTO customerDynamicAddDTO = new CustomerDynamicAddDTO();
                    customerDynamicAddDTO.setCorpid(corpid);
                    customerDynamicAddDTO.setUserId(creatorId);
                    customerDynamicAddDTO.setCustomerId(customerId);
                    customerDynamicAddDTO.setCustomerName(customerName);
                    customerDynamicAddDTO.setMemo(communicateMemo);
                    customerDynamicAddDTO.setCommunicateBusinessText(newPaasFormDataEntity.getSerialNo());
                    customerDynamicAddDTO.setCommunicateBusinessType(XbbRefTypeEnum.REFUND.getCode());
                    customerDynamicAddDTO.setDataId(newPaasFormDataEntity.getId());
                    customerDynamicAddDTO.setLogType(ProjectLogEnum.REFUND_CREATE.getSubType());
                    customerDynamicAddDTO.setDistributorMark(DistributorMarkEnum.DISTRIBUTOR.getCode());
                    customerCommunicateService.addCustomerDynamic(customerDynamicAddDTO);
                } else {
                    DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(saasFormSaveDTO.getBusinessType());
                    transactionHelp.afterCommitOrCommitNow(p->{
                        dynamicStrategy.save(DynamicSaveDTO.initDynamicSaveDTO(newPaasFormDataEntity.getId(), newPaasFormDataEntity.getFormId(), saasFormSaveDTO, creatorUser, null));
                    });
                }
            } catch (Exception e) {
                LOG.error("退货退款创建动态失败：", e);
            }
//                } catch (Exception e) {
//                    LOG.error("退货退款afterSave方法报错", e);
//                }
//            };
//            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
                List<UpdateDataEntity> list = new ArrayList<>();
                JSONObject jsonData = new JSONObject();
                JSONArray jsonArray = newRefundEntityExt.getData().getJSONArray(RefundEnum.PRODUCTS.getAttr());
                if(Objects.nonNull(jsonArray) && jsonArray.size() > BasicConstant.ZERO){
                    jsonData.put(ReturnEnum.ORDER_STATUS.getAttr(), ReturnStatusEnum.PROCESSING.getCode());
                    couponService.returnCoupon(contractEntityExt, refundData, corpid);
                }else{
                    jsonData.put(ReturnEnum.ORDER_STATUS.getAttr(), ReturnStatusEnum.COMPLETED.getCode());
                }
                UpdateDataEntity updateDataEntity = ExplainUtil.getUpdateData(refundEntityExt.getId(), jsonData, corpid);
                list.add(updateDataEntity);
                refundModel.updateBatch(list, corpid);

                // 退货单审核通过消息推送
            Runnable runnable = () -> {
                Integer businessTYpe = XbbRefTypeEnum.REFUND.getCode();
                try {
                    String type = refundData.getString(ReturnEnum.REFUND_TYPE.getAttr());
                    List<String> pushDistributorUserList = new ArrayList<>();
                    if (ReturnTypeEnum.AUTONOMOUS_RETURN.getCode().equals(type)) {
                        pushDistributorUserList = Collections.singletonList(refundData.getString(ReturnEnum.ORDERER_ID.getAttr()));
                    } else if (ReturnTypeEnum.VALET_RETRUN.getCode().equals(type)) {
                        // 代客下单消息推送
                        pushDistributorUserList = pushHelper.getDistributorUserIdListByPushSetRule(corpid, refundData.getLongValue(ReturnEnum.LINK_DISTRIBUTOR.getAttr()));
                    }
                    PushRefTypePojo.Options options = new PushRefTypePojo.Options(refundEntityExt.getAppId(), refundEntityExt.getMenuId(), refundEntityExt.getFormId(), refundEntityExt.getDataId(), Collections.singletonList(refundEntityExt.getDataId()), SaasMarkEnum.SAAS.getCode(), businessTYpe, businessTYpe);
                    // 订货单消息推送到经销商
                    DistributorMessageRabbitMqDTO distributorMessageRabbitMqDTO = new DistributorMessageRabbitMqDTO(corpid, pushDistributorUserList, Collections.singletonList(refundEntityExt.getDataId()), 0, null, I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_REVIEW_TITLE), String.format(I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_REVIEW_CONTENT), refundEntityExt.getSerialNo()), null, options, DistributorMarkEnum.DISTRIBUTOR.getCode());
                    baseProducer.sendMessage(PushTypeEnum.DISTRIBUTOR_REFUND_REVIEW_PUSH, distributorMessageRabbitMqDTO);
                } catch (Exception e) {
                    LOG.error("退货单审核通过消息推送", e);
                }
            };
            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
        } else {
            // 更新退货产品
            Map<Long, Double> changeNumMap = refundServiceImpl.setRefundProducts(newRefundEntityExt);
            JSONArray jsonArray = newRefundEntityExt.getData().getJSONArray(RefundEnum.PRODUCTS.getAttr());
            List<Long> refList = new ArrayList<>();
            Map<Long, Double> refNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (Objects.nonNull(jsonArray)) {
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    // 上游单据，原合同产品表ID
                    Long refProductId = FastJsonHelper.getLongFromFormData(jsonObject, BusinessConstant.REF_PRODUCT_ID);
                    if (Objects.nonNull(refProductId)) {
                        refList.add(refProductId);
                        refNumMap.put(refProductId, changeNumMap.getOrDefault(refProductId, FastJsonHelper.getDoubleFromFormData(jsonObject, ContractProductEnum.NUM.getAttr())));
                    }
                }
                // 原先的产品变化
                Iterator iterator = changeNumMap.keySet().iterator();
                while (iterator.hasNext()) {
                    Long contractProductId = (Long)iterator.next();
                    Double changeNum = changeNumMap.get(contractProductId);
                    if(!refList.contains(contractProductId)){
                        refList.add(contractProductId);
                        refNumMap.put(contractProductId, changeNum);
                    }
                }
            }
            if (!refList.isEmpty()) {
                boolean ifJXCOpen = ifJXCOpen(corpid);
                List<ContractProductEntity> contractProductEntityList = contractProductModel.getContractProductByContractIdIn(corpid, Collections.singletonList(contractId));

                if(ifJXCOpen){
                    JSONObject contractData = contractEntityExt.getData();
                    List<Long> outstockIds = FastJsonHelper.getJsonArrOrDefaultFromFormData(contractData, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                    // 未出库就不执行
                    if(!outstockIds.isEmpty()){
                        // 处理出库产品表和原合同产品表
                        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        params.put("corpid", corpid);
                        params.put("outstockIdIn", outstockIds);
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(params);
                        Map<Long, Double> refNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        for(OutstockProductEntity item : outstockProductEntities){
                            // 销售出库产品表，上游单据合同ID
                            if (refNumMap.containsKey(item.getId())) {
                                item.setInstockNum(Arith.add(item.getInstockNum() == null ? 0D : item.getInstockNum(), refNumMap.get(item.getId())));
                                refNumsMap.put(item.getRefProductId(), Arith.add(refNumMap.get(item.getId()),refNumsMap.getOrDefault(item.getRefProductId(), 0D)));
                            }
                        }
                        outstockProductModel.updateBatch(outstockProductEntities, corpid);
                        if (!refNumsMap.isEmpty()){
                            for (ContractProductEntity item : contractProductEntityList) {
                                Double instockNum = item.getInstockNum() == null ? 0D : item.getInstockNum();
                                if (refNumsMap.containsKey(item.getId())) {
                                    item.setInstockNum(Arith.add(instockNum, refNumsMap.getOrDefault(item.getId(), 0D)));
                                }
                            }
                            contractProductModel.updateBatch(contractProductEntityList, corpid);
                        }
                    }
                } else {
                    // 处理原合同产品表
                    /*Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    params.put("corpid", corpid);
                    params.put("idIn", refList);
                    params.put("del", DelEnum.NORMAL.getDel());
                    List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);*/
                    contractProductEntityList.forEach(item -> {
                        if (refNumMap.containsKey(item.getId())) {
                            item.setInstockNum(Arith.add(item.getInstockNum(), refNumMap.get(item.getId())));
                        }
                    });
                    contractProductModel.updateBatch(contractProductEntityList, corpid);
                }
            }

            Long redContractId = FastJsonHelper.getLongOrDefaultFromFormData(newRefundEntityExt.getData(), RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery(FieldTypeEnum.DATAID.getAlias(),redContractId));
            boolQueryBuilder.filter(termQuery("del", 0));
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(boolQueryBuilder);
            PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
            SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
            searchRequest.source(sourceBuilder);
            XbbAggregatedPage<ContractEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ContractEntityExt.class);
            ContractEntityExt redContractEntity = new ContractEntityExt();
            for (PaasFormDataEntity entity : esEntities.getContent()) {
                BeanUtil.copyProperties(entity, redContractEntity);
            }
            // 更新红冲合同的合同成本，合同毛利，现金毛利(包含新建和编辑)
            redContractEntity.setFlowStatus(newRefundEntityExt.getFlowStatus());
            refundServiceImpl.updateRedContract(jsonArray,corpid,redContractEntity,contractEntityExt,newRefundEntityExt.getData(),returnAmount,isNew, newRefundEntityExt.getId());
            if (BasicConstant.ONE.equals(saasFormSaveDTO.getIsFromProcess()) && Objects.equals(newRefundEntityExt.getFlowStatus(), FlowStatusEnum.PASS.getType())) {
                // 退货单审核通过消息推送
                JSONObject refundData = newRefundEntityExt.getData();
                Runnable runnable = () -> {
                    Integer businessTYpe = XbbRefTypeEnum.REFUND.getCode();
                    try {
                        String type = refundData.getString(ReturnEnum.REFUND_TYPE.getAttr());
                        List<String> pushDistributorUserList = new ArrayList<>();
                        if (ReturnTypeEnum.AUTONOMOUS_RETURN.getCode().equals(type)) {
                            pushDistributorUserList = Collections.singletonList(refundData.getString(ReturnEnum.ORDERER_ID.getAttr()));
                        } else if (ReturnTypeEnum.VALET_RETRUN.getCode().equals(type)) {
                            // 代客下单消息推送
                            pushDistributorUserList = pushHelper.getDistributorUserIdListByPushSetRule(corpid, refundData.getLongValue(ReturnEnum.LINK_DISTRIBUTOR.getAttr()));
                        }
                        PushRefTypePojo.Options options = new PushRefTypePojo.Options(newRefundEntityExt.getAppId(), newRefundEntityExt.getMenuId(), newRefundEntityExt.getFormId(), newRefundEntityExt.getDataId(), Collections.singletonList(newRefundEntityExt.getDataId()), SaasMarkEnum.SAAS.getCode(), businessTYpe, businessTYpe);
                        // 订货单消息推送到经销商
                        DistributorMessageRabbitMqDTO distributorMessageRabbitMqDTO = new DistributorMessageRabbitMqDTO(corpid, pushDistributorUserList, Collections.singletonList(newRefundEntityExt.getDataId()), 0, null, I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_REVIEW_TITLE), String.format(I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_REVIEW_CONTENT), newRefundEntityExt.getSerialNo()), null, options, DistributorMarkEnum.DISTRIBUTOR.getCode());
                        baseProducer.sendMessage(PushTypeEnum.DISTRIBUTOR_REFUND_REVIEW_PUSH, distributorMessageRabbitMqDTO);
                    } catch (Exception e) {
                        LOG.error("退货单审核通过消息推送", e);
                    }
                };
                threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
            }
        }

        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), newPaasFormDataEntity.getId(), newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), false);
    }

    @Override
    public void formatAddExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> explainList = formatExplainDTO.getExplainList();
        String corpid = formatExplainDTO.getCorpid();
        UserVO userVO = formatExplainDTO.getLoginUser();
        Set<String> permSet = userVO.getPermSet();
        FilterAttrOnOffJXCDTO filterAttrOnOffJXCDTO = new FilterAttrOnOffJXCDTO();
        BeanUtil.copyProperties(formatExplainDTO, filterAttrOnOffJXCDTO);
        filterAttrOnOffJXCDTO.setFieldAttrEntityList(explainList);
        filterAttrOnOffJXCDTO.setOperatePageCode(OperatePageEnum.NEW.getCode());
        refundModel.filterAttrOnOffJXC(filterAttrOnOffJXCDTO);
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            Integer fieldType = fieldAttrEntity.getFieldType();
            String attr = fieldAttrEntity.getAttr();
            if (Objects.equals(fieldType, FieldTypeEnum.SELECT_PRODUCT.getType())) {
                explainHelp.formatSelectProductExplains(fieldAttrEntity, XbbRefTypeEnum.REFUND, corpid, OperatePageEnum.NEW.getCode(), false);
            }
            if (Objects.equals(attr, RefundEnum.SIGN_USER.getAttr())) {
                fieldAttrEntity.setDefaultAttr(defaultAttrHelp.setUserDefaultAttrPoJo(formatExplainDTO.getUserId(), formatExplainDTO.getLoginUserName(),formatExplainDTO.getLoginUser().getAvatar()));
            } else if(Objects.equals(attr, RefundEnum.PAYMENT_SHEETS.getAttr())) {
                //回款单新增权限判断
                if(!permSet.contains(ProPermissionAliasEnum.PAYMENT_SHEET_ADD.getAlias())) {
                    fieldAttrEntity.setEditable(BasicConstant.ZERO);
                }
            } else if(Objects.equals(attr, RefundEnum.PAYMENTS.getAttr())) {
                //红冲应收款权限判断
                if(!permSet.contains(ProPermissionAliasEnum.RED_RECEIVABLES.getAlias())) {
                    fieldAttrEntity.setEditable(BasicConstant.ZERO);
                }
            } else if(Objects.equals(attr, RefundEnum.INVOICES.getAttr())) {
                //红冲/作废发票按钮权限判断
                if(!permSet.contains(ProPermissionAliasEnum.INVOICE_CANCEL.getAlias()) && !permSet.contains(ProPermissionAliasEnum.INVOICE_RED.getAlias())) {
                    fieldAttrEntity.setEditable(BasicConstant.ZERO);
                }
            }
        }
    }

    private void validateDataProduct(JSONArray productArray, String corpid, Long contractId, Long refundId) throws XbbException {
        Set<Long> pageProductIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Double> productNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 是否需要合并
        boolean needMerge = false;
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject productObj = productArray.getJSONObject(i);
            Long refProductId = productObj.getLong(BusinessConstant.REF_PRODUCT_ID);
            if (Objects.isNull(refProductId)) {
                needMerge = true;
                break;
            }
        }
        for (Object object:productArray) {
            JSONObject jsonObject = (JSONObject) object;
            Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            pageProductIds.add(productId);
            Double productNum = jsonObject.getDouble(SelectProductEnum.NUM.getAttr());
            String key;
            if (needMerge) {
                key = productId.toString();
            } else {
                Long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
                key = productId + "_" + refProductId;
            }
            Double num = productNumMap.getOrDefault(key,0D);
            num += productNum;
            productNumMap.put(key,num);
        }
        Map<Long,String> pageProductMap = formDataValidateProductHelp.productExit(corpid,new ArrayList<>(pageProductIds));
        //开了退出库，没开退合同
        Map<String,Double> unRefundMap = formDataValidateProductHelp.getContractUnRefund(corpid,contractId,refundId,needMerge);

        // 24187 【退货退款】未开启进销存，编辑退货退款提示不正确
        Boolean isJxcUse = paasAppService.validateAppEnable(null, XbbRefTypeEnum.JXC.getAlias(), SaasMarkEnum.SAAS.getCode(), corpid);
        if (isJxcUse) {
            formDataValidateProductHelp.stockProductNumLegalCheck(false, unRefundMap,productNumMap,pageProductMap, I18nMessageUtil.getMessage(I18nStringConstant.REFUND_PRODUCT_NUM_ERROR));
        }
    }

    /**
     * 金额校验
     *
     * @param corpid       公司id
     * @param refundAmount 退款金额
     * @param returnAmount 退货金额
     * @param contractId   公司id
     * @param refundId     退货单id
     * @throws XbbException 异常
     */
    private void refundAmountJudgement(String corpid, Double refundAmount, Double returnAmount, Long contractId, Long refundId, String serialNo) throws XbbException {
        if (refundAmount < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215022);
        }
        if (returnAmount < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215023);
        }
        if (refundAmount > returnAmount) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215020);
        }
        ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.PASS.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
        //param.put(ParameterConstant.NEG_ID, refundId);
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(XbbRefTypeEnum.REFUND.getCode(), RefundEnum.CONTRACT_ID.getAttr(), contractId, param, IndexTypeEnum.IDX_SAAS_REFUND);
        //退货金额合计
        Double returnAmountSum = returnAmount;
        for (PaasFormDataEntityExt refund : paasFormDataEntityExts) {
            if(!Objects.equals(serialNo, refund.getSerialNo())){
                returnAmountSum = Arith.add(returnAmountSum, FastJsonHelper.getDoubleOrDefaultFromFormData(refund.getData(), RefundEnum.RETURN_AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE));
            }
        }
        Double contractAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractEntityExt.getData(), ContractEnum.AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
        if (Arith.compare(contractAmount, refundAmount) < BasicConstant.ZERO_DOUBLE) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215030);
        }
    }


    /**
     * 判断进销存是否开启
     *
     * @param corpid 公司Id
     * @return boolean true:开启进销存。false：关闭进销存
     * @author youli.chen
     * @date 2019/3/7 8:50
     * @since v1.0
     */
    @Override
    public boolean ifJXCOpen(String corpid) throws XbbException {
        PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
        Integer enable;
        if (paasAppEntity == null) {
            LOG.error("RefundServiceImpl 该公司进销存业务没有数据" + corpid);
            // 默认关闭
            enable = BasicConstant.ZERO;
        } else {
            enable = paasAppEntity.getEnable();
        }
        return Objects.equals(BasicConstant.ONE, enable);
    }

    @Override
    public ReturnEditAttrUpdateVO batchEditAttr(ReturnEditAttrUpdateDTO returnEditAttrUpdateDTO) throws XbbException {
        ReturnEditAttrUpdateVO returnEditAttrUpdateVO = new ReturnEditAttrUpdateVO();
        List<RefundEntityExt> refundEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        try {
            List<Long> idIn = returnEditAttrUpdateDTO.getDataIdList();
            List<RefundUpdateDTO> refundUpdateDTOS = new ArrayList<>();
            idIn.forEach((item)->{
                RefundUpdateDTO refundUpdateDTO = new RefundUpdateDTO();
                refundUpdateDTO.setId(item);
                JSONObject data = ProSaveHelp.getBatchUpdateData(returnEditAttrUpdateDTO.getFieldEditedList());
                refundUpdateDTO.setData(data);
                refundUpdateDTOS.add(refundUpdateDTO);
            });
            if (!refundUpdateDTOS.isEmpty()) {
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", returnEditAttrUpdateDTO.getCorpid());
                param.put("idIn", returnEditAttrUpdateDTO.getDataIdList());
                refundEntityList = refundModel.findEntitys(param);
                if (Objects.isNull(refundEntityList)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
                }

                RefundUpdateBatchDTO refundUpdateBatchDTO = new RefundUpdateBatchDTO();
                BeanUtil.copyProperties(returnEditAttrUpdateDTO, refundUpdateBatchDTO);
                refundUpdateBatchDTO.setRefundUpdateList(refundUpdateDTOS);
                refundService.updateBatch(refundUpdateBatchDTO);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("refundServiceImpl.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        // 批量编辑日志
        List<String> updataItemList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (RefundEntityExt item : refundEntityList) {
            dataIdList.add(item.getId());
            JSONObject data = item.getData();
            String serialNo = item.getSerialNo();
            String opObjectName = data.getString(RefundEnum.REFUND_NAME.getAttr());
            StringBuilder sb = new StringBuilder();
            opObjectName = opObjectName == null ? serialNo : sb.append(serialNo).append("（").append(opObjectName).append("）").toString();
            updataItemList.add(opObjectName);
        }
        String updataItem = StringUtils.join(updataItemList, "，");
        String userId = returnEditAttrUpdateDTO.getUserId();
        String corpid = returnEditAttrUpdateDTO.getCorpid();
        String loginUserName = returnEditAttrUpdateDTO.getLoginUserName();
        // 标签特殊处理
        Integer fieldType = returnEditAttrUpdateDTO.getFieldType();
        Boolean isFieldDependence = returnEditAttrUpdateDTO.getIsFieldDependence();
        logHelp.analysisLabel(corpid, fieldType, isFieldDependence,returnEditAttrUpdateDTO.getLogFieldEditedList());

        String changedLogItemsStr = logHandleHelp.getChangedLogItemsStr(returnEditAttrUpdateDTO.getLogFieldEditedList());
        if(dataIdList.size() > 1 ){
            String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_BATCH_ATTR), loginUserName, XbbRefTypeEnum.REFUND.getName(),
                    changedLogItemsStr, dataIdList.size());
            List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            InfoArrPojo infoArrPojo = new InfoArrPojo();
            infoArrPojo.setTitle(XbbRefTypeEnum.REFUND.getName());
            infoArrPojo.setContent(updataItem);
            infoArrPojoList.add(infoArrPojo);
            mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.REFUND, OperateTypeEnum.EDIT,
                    "", "", memo, returnEditAttrUpdateDTO.getHttpHeader());
        } else if (Objects.equals(dataIdList.size(), 1)){
            String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_ATTR), loginUserName, XbbRefTypeEnum.REFUND.getName(), updataItem,
                    changedLogItemsStr);
            mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.REFUND, OperateTypeEnum.EDIT,
                    dataIdList.get(0).toString(), updataItem, memo, returnEditAttrUpdateDTO.getHttpHeader());
        }

        return returnEditAttrUpdateVO;
    }

    @Override
    public ReturnDeleteBatchVO deleteBatch(ReturnDeleteBatchDTO returnDeleteBatchDTO) throws XbbException {
        ReturnDeleteBatchVO returnDeleteBatchVO = new ReturnDeleteBatchVO();
        // TODO 删除权限校验
        List<Long> idIn = returnDeleteBatchDTO.getDataIdList();
        if (idIn != null && idIn.size() > BasicConstant.MAX_DEL_BATCH_COUNT) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100079, String.format(SystemErrorCodeEnum.API_ERROR_100079.getMsg(), BasicConstant.MAX_DEL_BATCH_COUNT));
        }
        String corpid = returnDeleteBatchDTO.getCorpid();
        List<Long> redContractIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> oldContractIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> deleteIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        Map<String, Object> param = BeanUtil.convertBean2Map(returnDeleteBatchDTO, true);
        param.put("idIn", idIn);
        param.put("corpid", corpid);
        param.put("del", 0);
        List<RefundEntityExt> refundExtList = refundModel.findEntitys(param);
        if (Objects.isNull(refundExtList)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        // 序列号关联表单删除校验
        if (CollectionUtils.isNotEmpty(idIn)) {
            productSerialService.preCheckDelSerial(idIn, corpid, XbbRefTypeEnum.REFUND.getCode());
        }

        List<Long> conId = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> physicalDelIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        physicalDelIds.addAll(idIn);
        Map<String, String> noAndName= new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与红冲合同对应map
        Map<Long, List<Long>> contractIdAndRedContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 合同与退货金额对应map
        Map<Long, Double> contractIdAndReturnCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        //key为红冲合同Id,value为退款单id,一对一关系
        Map<Long, Long> redContractIdAndRefundId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> refundIdAndContractId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (RefundEntityExt item : refundExtList) {
            deleteIdIn.add(item.getId());
            JSONObject itemData = item.getData();
            Long redConId =  itemData.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            redContractIdIn.add(redConId);
            redContractIdAndRefundId.put(redConId,item.getId());
            Long oldConId = FastJsonHelper.getLongOrDefaultFromFormData(itemData, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            refundIdAndContractId.put(item.getId(), oldConId);
            oldContractIdIn.add(oldConId);

            if (physicalDelIds.contains(item.getId())) {
                physicalDelIds.remove(item.getId());
            }

            if(contractIdAndRedContractMap.containsKey(oldConId)){
                List<Long> redConIdList = contractIdAndRedContractMap.get(oldConId) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(oldConId);
                List<Long> idList = new ArrayList<>(redConIdList);
                idList.add(redConId);
                contractIdAndRedContractMap.put(oldConId, idList);
            } else {
                contractIdAndRedContractMap.put(oldConId, Arrays.asList(redConId));
            }
            Double returnCost = FastJsonHelper.getDoubleOrDefaultFromFormData(itemData, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);
            if(contractIdAndReturnCostMap.containsKey(oldConId)){
                Double cost = contractIdAndReturnCostMap.get(oldConId) == null ? 0D : contractIdAndReturnCostMap.get(oldConId);
                returnCost = Arith.add(returnCost, cost);
                contractIdAndReturnCostMap.put(oldConId, returnCost);
            } else {
                contractIdAndReturnCostMap.put(oldConId, returnCost);
            }

            String no = item.getSerialNo();
            String name = FastJsonHelper.getStringOrDefaultFromFormData(itemData, RefundEnum.REFUND_NAME.getAttr(), "");
            noAndName.put(no, name);
        }

        // 查询出所有关联原合同的退货退款，并筛除出当前需要删除的红冲合同
        Map<Long, List<Long>> allContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 查询出所有关联原合同的退货金额，并筛除出当前需要删除的红冲合同
        Map<Long, Double> allContractCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        BoolQueryBuilder oldQueryBuilder = boolQuery();
        oldQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        oldQueryBuilder.filter(termsQuery(RefundEnum.getEsAttr4Keyword(RefundEnum.CONTRACT_ID),oldContractIdIn));
        oldQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        oldQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(oldQueryBuilder);
        PageRequest page = EsUtil.setPage(builder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest search = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        search.source(builder);
        XbbAggregatedPage<PaasFormDataEntity> entities = xbbElasticsearchRestTemplate.queryForPages(page, search, PaasFormDataEntity.class);
        for (PaasFormDataEntity entity : entities.getContent()) {
            JSONObject data = entity.getData();
            Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            Long redContractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);
            Double returnCost = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);

            if(allContractMap.containsKey(contractId)){
                List<Long> redConIdList = allContractMap.get(contractId) == null ? new ArrayList<>() : allContractMap.get(contractId);
                List<Long> idList = new ArrayList<>(redConIdList);
                idList.add(redContractId);
                allContractMap.put(contractId, idList);
            } else {
                allContractMap.put(contractId, Arrays.asList(redContractId));
            }

            if(allContractCostMap.containsKey(contractId)){
                Double cost = allContractCostMap.get(contractId) == null ? 0D : allContractCostMap.get(contractId);
                returnCost = Arith.add(returnCost, cost);
                allContractCostMap.put(contractId, returnCost);
            } else {
                allContractCostMap.put(contractId, returnCost);
            }
        }

        // 所有的红冲合同（排除删除的）
        Iterator allEntries = allContractMap.entrySet().iterator();
        while(allEntries.hasNext()) {
            Map.Entry entry = (Map.Entry) allEntries.next();
            Long key = (Long) entry.getKey();
            List<Long> allRedConIdList = allContractMap.get(key);
            // 不存在不包含的情况，不做处理
            if(contractIdAndRedContractMap.containsKey(key)){
                List<Long> redConIdList = contractIdAndRedContractMap.get(key) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(key);
                List<Long> idList = new ArrayList<>(allRedConIdList);
                // 取差集
                idList.removeAll(redConIdList);
                contractIdAndRedContractMap.put(key, idList);
            }
        }

        // 所有的退货金额（排除删除的）
        Iterator allCostEntries = allContractCostMap.entrySet().iterator();
        while(allCostEntries.hasNext()) {
            Map.Entry entry = (Map.Entry) allCostEntries.next();
            Long key = (Long) entry.getKey();
            Double allCost = allContractCostMap.get(key);
            // 不存在不包含的情况，不做处理
            if(contractIdAndReturnCostMap.containsKey(key)){
                Double cost = contractIdAndReturnCostMap.get(key) == null ? 0D : contractIdAndReturnCostMap.get(key);
                allCost = Arith.sub(allCost, cost);
                allContractCostMap.put(key, allCost);
            }
        }

        // 所有对应的合同实体
        List<ContractEntityExt> contractList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> contractIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        BoolQueryBuilder entityQueryBuilder = boolQuery();
        entityQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        entityQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), oldContractIdIn));
        entityQueryBuilder.filter(termQuery("del", 0));
        entityQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(entityQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ContractEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ContractEntityExt.class);
        for (ContractEntityExt entity : esEntities.getContent()) {
            Long contractId = entity.getDataId();
            contractList.add(entity);
            contractIdList.add(contractId);
        }

        // 合同与红冲合同退货产品成本对应map
        Map<Long, Double> contractIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 这里查询的都是之前的数据（排除删除的）
        boolean ifJXCOpen = ifJXCOpen(corpid);
        Iterator entries = contractIdAndRedContractMap.entrySet().iterator();
        while(entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            Long key = (Long) entry.getKey();
            List<Long> redConIdList = contractIdAndRedContractMap.get(key);
            Double costAmount = BasicConstant.ZERO_DOUBLE;
            if(redConIdList.size() > 0) {
                Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Object> redParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                redParam.put("corpid", corpid);
                redParam.put("contractIdIn",redConIdList);
                redParam.put("del", 0);
                // 拿到红冲合同的所有产品
                List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(redParam);
                // 退货产品ID以及对应的数量
                for(ContractProductEntity entity : contractProductEntityList){
                    Long pageProductId = entity.getProductId();
                    Double productNum = entity.getProductNum() == null ? 0D : Math.abs(entity.getProductNum());
                    if(productIdAndNumMap.containsKey(pageProductId)){
                        Double num = productIdAndNumMap.get(pageProductId) == null ? 0D : productIdAndNumMap.get(pageProductId);
                        productNum = Arith.add(productNum, num);
                    }
                    productIdAndNumMap.put(pageProductId, productNum);
                }
                if(ifJXCOpen){
                    // 如果退货退款能删除，说明在入库单那里已经处理好合同的成本计算问题，这里就不做考虑
                    costAmount = BasicConstant.ZERO_DOUBLE;
                } else if(!ifJXCOpen){
                    // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE),201));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID), key));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT.getType()));
                    List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                    List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT,boolQueryBuilder, PaasFormDataEntity.class, fieldList);
                    if(list.size() > 0) {
                        List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                        for (ContractProductEntity contractProductEntity : contractProductEntities) {
                            Long productId = contractProductEntity.getProductId();
                            Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                            if(productIdAndNumMap.containsKey(productId)){
                                Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                                costAmount = Arith.add(costAmount, productCost);
                            }
                        }
                    }
                }
            }
            contractIdAndCostMap.put(key, costAmount);
        }

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termQuery("data." + OutstockEnum.TYPE.getAttr(), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()));
        boolQueryBuilder.filter(termsQuery("data." + OutstockEnum.REF_ID.getAttr(), oldContractIdIn));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OUTSTOCK.getType()));
        List<PaasFormDataEntityExt> outstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(OutstockEnum.getAttrConnectData(OutstockEnum.REF_ID), FieldTypeEnum.DATAID.getAlias()));

        // 根据出库单获取对应的产品
        List<Long> dataIdIn = new ArrayList<>();
        outstockList.forEach(outstock -> dataIdIn.add(outstock.getDataId()));
        Map<String, Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockParam.put("corpid", corpid);
        outstockParam.put("del", 0);
        outstockParam.put("outstockIdIn", dataIdIn);
        List<OutstockProductEntity> outstockAllProductList = outstockProductModel.findEntitys(outstockParam);

        // 合同和关联的出库单的对应关系
        Map<Long, List<Long>> contractOutstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt contractEntity : contractList) {
            Long contractId = contractEntity.getId();
            List<Long> outstockIdList = contractOutstockMap.get(contractId);
            if (outstockIdList == null) {
                outstockIdList = new ArrayList<>();
            }
            for (PaasFormDataEntityExt outstock : outstockList) {
                Long refId = outstock.getData().getLong(OutstockEnum.REF_ID.getAttr());
                if (Objects.equals(contractId, refId)) {
                    outstockIdList.add(outstock.getDataId());
                }
            }
            contractOutstockMap.put(contractId, outstockIdList);
        }

        // 合同和出库产品的对应关系
        Map<Long, List<OutstockProductEntity>> contractOutstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt contractEntity : contractList) {
            Long contractId = contractEntity.getId();
            List<Long> outstockIdList = contractOutstockMap.get(contractId);
            List<OutstockProductEntity> outstockProductEntityList = contractOutstockProductMap.get(contractId);
            if (outstockProductEntityList == null) {
                outstockProductEntityList = new ArrayList<>();
            }
            for (OutstockProductEntity outstockProductEntity : outstockAllProductList) {
                Long outstockId = outstockProductEntity.getOutWarehouseId();
                if (outstockIdList.contains(outstockId)) {
                    outstockProductEntityList.add(outstockProductEntity);
                }
            }
            contractOutstockProductMap.put(contractId, outstockProductEntityList);
        }

        // 合同和关联产品的对应关系
        List<ContractProductEntity> contractProList = contractProductModel.getContractProductByContractIdIn(corpid, contractIdList);
        Map<Long, List<ContractProductEntity>> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt contractEntity : contractList) {
            Long contractId = contractEntity.getId();
            List<ContractProductEntity> contractProductList = contractProductMap.get(contractId);
            if (contractProductList == null) {
                contractProductList = new ArrayList<>();
            }
            for (ContractProductEntity contractProductEntity : contractProList) {
                if (Objects.equals(contractProductEntity.getContractId(), contractId)) {
                    contractProductList.add(contractProductEntity);
                }
            }
            contractProductMap.put(contractId, contractProductList);
        }

        // TODO 如果该退货退款合同有已生成退货入库单时，不允许删除(批量时只要有一个有问题就返回错误)

        List<Long> refundIdList = new ArrayList<>();
        List<String> refundSerialNos = new ArrayList<>();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = boolQuery();
        queryBuilder.filter(termQuery("corpid.keyword", corpid));
        queryBuilder.filter(termsQuery("data." + RefundInstockEnum.REF_ID.getAttr(), idIn));
        queryBuilder.filter(termQuery("data." + RefundInstockEnum.TYPE.getAttr(), InstockTypeEnum.RED_CONTRACT_INSTOCK.getCode()));
        queryBuilder.filter(termQuery("del", 0));
        // 设置join_field
        queryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND_INSTOCK.getType()));
        searchSourceBuilder.query(queryBuilder);
        List<PaasFormDataEntityExt> entityExts = paasEsModel.list(searchSourceBuilder, IndexTypeEnum.IDX_SAAS_REFUND_INSTOCK, Collections.singletonList(RefundInstockEnum.REF_ID.getAttr()), null, null);
        if (!Objects.equals(entityExts.size(), BasicConstant.ZERO)) {
            entityExts.forEach(item -> {
                Long refundId = item.getData().getLong(RefundInstockEnum.REF_ID.getAttr());
                refundIdList.add(refundId);
            });
            for (RefundEntityExt refundEntityExt : refundExtList) {
                if (refundIdList.contains(refundEntityExt.getId())) {
                    refundSerialNos.add(refundEntityExt.getSerialNo());
                }
            }
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215031, String.format(I18nMessageUtil.getMessage(RefundErrorCodeEnum.API_ERROR_215031.getMsg()), refundSerialNos.toString()));
        }
        try {
            if (!physicalDelIds.isEmpty()) {
                if(BasicConstant.ONE.equals(returnDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(idIn.size())){
                    paasEsModel.delete(physicalDelIds.get(0),corpid, IndexTypeEnum.IDX_SAAS_REFUND,null);
                }else {
                    // 删除es中存在，数据库不存在的数据
                    paasEsModel.deleteBatch(physicalDelIds, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_REFUND);
                }
            }
            if (!deleteIdIn.isEmpty()) {
                if(BasicConstant.ONE.equals(returnDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(deleteIdIn.size())){
                    refundModel.deleteByKey(deleteIdIn.get(0),corpid);
                }else {
                    refundModel.deleteBatch(deleteIdIn, corpid, DelEnum.DELETE.getDel());
                }
                returnDeleteBatchVO.setDeleteIds(deleteIdIn);

                // 删除退货退款关联客户
                RefundUserDeleteBatchDTO refundUserDeleteBatchDTO = new RefundUserDeleteBatchDTO();
                BeanUtil.copyProperties(returnDeleteBatchDTO, refundUserDeleteBatchDTO);
                refundUserDeleteBatchDTO.setRefundIdIn(deleteIdIn);
                refundUserService.deleteBatch(refundUserDeleteBatchDTO);

                // 删除作废发票
                try {
                    refundInvoiceModel.deleteBatchByRefundIdIn(corpid, deleteIdIn);
                } catch (Exception e) {
                    LOG.error("删除退货退款关联作废发票失败：", e);
                    throw new XbbException(RefundErrorCodeEnum.API_ERROR_215028);
                }
                //序列号删除
                productSerialService.deleteSerial(corpid, deleteIdIn, XbbRefTypeEnum.REFUND.getCode());
            }
            ContractProductListVO redContractProductList = null;
            if (!redContractIdIn.isEmpty()) {

                // 删除合同业绩分配
                ContractPerformanceDeleteBatchDTO contractPerformanceDeleteBatchDTO = new ContractPerformanceDeleteBatchDTO();
                BeanUtil.copyProperties(returnDeleteBatchDTO, contractPerformanceDeleteBatchDTO, true);
                contractPerformanceDeleteBatchDTO.setContractIdIn(redContractIdIn);
                contractPerformanceService.deleteBatch(contractPerformanceDeleteBatchDTO);
                // 删除合同产品
                ContractProductDeleteBatchDTO contractProductDeleteBatchDTO = new ContractProductDeleteBatchDTO();
                BeanUtil.copyProperties(returnDeleteBatchDTO, contractProductDeleteBatchDTO, true);
                contractProductDeleteBatchDTO.setContractIdIn(redContractIdIn);
                //后面要用到 redContractProductList
                ContractProductListDTO contractProductListDTO = new ContractProductListDTO();
                contractProductListDTO.setCorpid(corpid);
                contractProductListDTO.setDel(DelEnum.NORMAL.getDel());
                contractProductListDTO.setContractIdIn(redContractIdIn);
                redContractProductList = contractProductService.findContractProductList(contractProductListDTO);
                contractProductService.deleteBatch(contractProductDeleteBatchDTO);
                // 合同那边的优化(删除红冲合同)
                try {
                    contractModel.deleteBatch(redContractIdIn, corpid);
                } catch (Exception e) {
                    LOG.error("删除退货退款关联红冲合同失败：", e);
                    throw new XbbException(RefundErrorCodeEnum.API_ERROR_215029);
                }
            }

            // 合同那边的优化(将原合同属性变更)
            if (!oldContractIdIn.isEmpty()) {
                // 查询合同还有没有关联的红冲合同
                for (Long contractId : oldContractIdIn) {
                    Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    params.put(ParameterConstant.CORPID, corpid);
                    params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                    List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(RedundantTemplateTypeEnum.REFUND.getCode(),
                            RefundEnum.CONTRACT_ID.getAttr(), contractId, params, IndexTypeEnum.IDX_SAAS_REFUND);
                    paasFormDataEntityExts.forEach((item) -> conId.add(item.getId()));
                }
                refundServiceImpl.returnContractData(contractList, conId, contractOutstockProductMap, contractProductMap, contractIdAndCostMap, allContractCostMap);

                // TODO 海滨 更新原合同的退货数量
                //更改合同产品表的已退货数量,只有新合同才更改
                if(redContractProductList != null &&
                        !CollectionUtils.isEmpty(redContractProductList.getContractProductList())){
                    List<ContractProductEntity> contractProductList = redContractProductList.getContractProductList();
//                    退货退款何销售出库单都是老数据
                    Map<Long, Long> allOldredContractIdAndRefundId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for (ContractProductEntity contractProductEntity : contractProductList) {
                        Long key = contractProductEntity.getContractId();
                        if(Objects.isNull(contractProductEntity.getRefProductId())){
                            if (!allOldredContractIdAndRefundId.containsKey(key)) {
                                allOldredContractIdAndRefundId.put(key, redContractIdAndRefundId.getOrDefault(key, 0L));
                            }
                            redContractIdAndRefundId.remove(key);
                        }
                    }
                    //获取需要合并的红冲产品数据
                    Map<Long, Double> redProductNums = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Map<Object, Double> oldRedProductNums = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    HashSet<Long> allOldContractIds = new HashSet<>();
                    if(!redContractIdAndRefundId.isEmpty() || !allOldredContractIdAndRefundId.isEmpty()){
                        //行对应计算删除的产品数量
                        for (ContractProductEntity contractProductEntity : contractProductList) {
                            if(redContractIdAndRefundId.containsKey(contractProductEntity.getContractId())){
                                Long refProductId = contractProductEntity.getRefProductId();
                                Double num = Arith.add(redProductNums.get(refProductId)==null?0L:redProductNums.get(refProductId),
                                        contractProductEntity.getProductNum());
                                redProductNums.put(refProductId, num);
                            }else if (allOldredContractIdAndRefundId.containsKey(contractProductEntity.getContractId())){
//                               退货退款和销售出库单都是老数据
                                Long contractId = refundIdAndContractId.getOrDefault(allOldredContractIdAndRefundId.get(contractProductEntity.getContractId()), 0L);
                                String key = contractId + "" + contractProductEntity.getProductId();
                                Double num = oldRedProductNums.getOrDefault(key, 0D);
                                num += contractProductEntity.getProductNum();
                                oldRedProductNums.put(key, num);
                                allOldContractIds.add(contractId);
                            }
                        }
                    }
                    PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
                    boolean isOpenJxc = false;
                    if (Objects.nonNull(paasAppEntity)) {
                        isOpenJxc = paasAppEntity.getEnable() == 1;
                    }
                    if (isOpenJxc) {
                        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        params.put("corpid", corpid);
                        params.put("idIn", redProductNums.keySet());
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(params);
                        Map<Long, Double> refundNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        HashSet<Long> refOutProductIds = new HashSet<>();
                        if (!CollectionUtils.isEmpty(outstockProductEntities)) {
                            for (OutstockProductEntity outstockProductEntity : outstockProductEntities) {
                                Long id = outstockProductEntity.getId();
                                if (redProductNums.containsKey(id)) {
                                    if (Objects.isNull(outstockProductEntity.getRefProductId())) {
                                        refOutProductIds.add(id);
                                    }else {
                                        Double num = refundNumsMap.getOrDefault(outstockProductEntity.getRefProductId(), 0D);
                                        num += redProductNums.get(id);
                                        refundNumsMap.put(outstockProductEntity.getRefProductId(), num);
                                        //由于红冲合同产品数量是负数，所以此处应add
                                        outstockProductEntity.setInstockNum(Arith.add(outstockProductEntity.getInstockNum(), redProductNums.get(id)));
                                        outstockProductEntity.setUpdateTime(DateTimeUtil.getInt());
                                    }
                                }

                            }
                            //更新销售出库单产品的已入库数量
                            outstockProductModel.updateBatch(outstockProductEntities, corpid);
                        }
                        if (!refundNumsMap.isEmpty()) {
                            params.put("idIn", refundNumsMap.keySet());
                            List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                            contractProductEntities.forEach(item -> {
                                if (refundNumsMap.containsKey(item.getId())) {
                                    //由于红冲合同产品数量是负数，所以此处应add
                                    item.setInstockNum(Arith.add(item.getInstockNum(), refundNumsMap.get(item.getId())));
                                }
                            });
                            contractProductModel.updateBatch(contractProductEntities, corpid);
                        }

                        if (!refOutProductIds.isEmpty()) {
//                            退货退款是新数据，出库单是老数据的情况
                            Map<Object, Double> refundProductNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            HashSet<Long> contractIds = new HashSet<>();
                            for (ContractProductEntity contractProductEntity : contractProductList) {
                                if(redContractIdAndRefundId.containsKey(contractProductEntity.getContractId())){
                                    Long refProductId = contractProductEntity.getRefProductId();
                                    if (refOutProductIds.contains(refProductId)) {
                                        Long refundId = redContractIdAndRefundId.get(contractProductEntity.getContractId());
                                        Long contractId = refundIdAndContractId.getOrDefault(refundId, 0L);
                                        contractIds.add(contractId);
                                        String key = contractId + "" + contractProductEntity.getProductId();
                                        Double num = refundProductNumsMap.getOrDefault(key, 0D);
                                        num += contractProductEntity.getProductNum();
                                        refundProductNumsMap.put(key, num);
                                    }
                                }
                            }
                            params.clear();
                            params.put("corpid", corpid);
                            params.put("contractIdIn", contractIds);
                            params.put("del", DelEnum.NORMAL.getDel());
                            List<ContractProductEntity> entitys = contractProductModel.findEntitys(params);
                            for (ContractProductEntity entity : entitys) {
                                String key = entity.getContractId() + "" + entity.getProductId();
                                Double amendNum = (-1) * refundProductNumsMap.getOrDefault(key, 0D);
                                Double instockNum ;
                                if (Arith.sub(entity.getInstockNum(), amendNum) > 0){
                                    instockNum = Arith.sub(entity.getInstockNum(), amendNum);
                                    refundProductNumsMap.remove(key);
                                }else {
                                    instockNum = 0D;
                                    refundProductNumsMap.put(key, Arith.sub(entity.getInstockNum(), amendNum));
                                }
                                entity.setInstockNum(instockNum);
                            }
                            contractProductModel.updateBatch(entitys, corpid);
                        }
                        if (!allOldContractIds.isEmpty()) {
//                            退货退款和销售出库都是老数据
                            params.clear();
                            params.put("corpid", corpid);
                            params.put("contractIdIn", allOldContractIds);
                            params.put("del", DelEnum.NORMAL.getDel());
                            List<ContractProductEntity> entitys = contractProductModel.findEntitys(params);
                            for (ContractProductEntity entity : entitys) {
                                String key = entity.getContractId() + "" + entity.getProductId();
                                Double amendNum = (-1) * oldRedProductNums.getOrDefault(key, 0D);
                                Double instockNum ;
                                if (Arith.sub(entity.getInstockNum(), amendNum) > 0){
                                    instockNum = Arith.sub(entity.getInstockNum(), amendNum);
                                    oldRedProductNums.remove(key);
                                }else {
                                    instockNum = 0D;
                                    oldRedProductNums.put(key, Arith.sub(entity.getInstockNum(), amendNum));
                                }
                                entity.setInstockNum(instockNum);
                            }
                            contractProductModel.updateBatch(entitys, corpid);
                        }
                    }else {
                        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        params.put("corpid", corpid);
                        params.put("idIn", redProductNums.keySet());
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(params);
                        if (!CollectionUtils.isEmpty(contractProductEntityList)) {
                            for (ContractProductEntity contractProductEntity : contractProductEntityList) {
                                Long id = contractProductEntity.getId();
                                if (redProductNums.containsKey(id)) {
                                    //由于红冲合同产品数量是负数，所以此处应add
                                    contractProductEntity.setInstockNum(Arith.add(contractProductEntity.getInstockNum(), redProductNums.get(id)));
                                    contractProductEntity.setUpdateTime(DateTimeUtil.getInt());
                                }

                            }
                            //更新销售出库单产品的已入库数量
                            contractProductModel.updateBatch(contractProductEntityList, corpid);
                        }
                    }
                }
            }
            // TODO 删除相关审批记录
            // 退货退款删除回滚
        } catch (Exception e) {
            LOG.error("refundServiceImpl.deleteBatch 执行出错：", e);
            refundServiceImpl.updateRollback(returnDeleteBatchDTO.getDataIdList(), corpid);
            redContractIdIn.addAll(oldContractIdIn);
            contractService.updateRollback(redContractIdIn, corpid);
            contractPerformanceService.updateRollbackByContractId(redContractIdIn, corpid);
            refundInvoiceModel.updateRollbackByRefundId(corpid, returnDeleteBatchDTO.getDataIdList());
            refundUserService.updateRollbackByRefundId(returnDeleteBatchDTO.getDataIdList(), corpid);

            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

//        // 消息推送
//        // 退货单审核不通过消息推送
//        if (BasicConstant.ONE.equals(fromProcess)) {
//            RefundEntityExt refundEntity = refundExtList.get(0);
//            JSONObject refundData = refundEntity.getData();
//            Runnable runnable = () -> {
//                Integer businessTYpe = XbbRefTypeEnum.REFUND.getCode();
//                try {
//                    String type = refundData.getString(ReturnEnum.REFUND_TYPE.getAttr());
//                    List<String> pushDistributorUserList = new ArrayList<>();
//                    if (ReturnTypeEnum.AUTONOMOUS_RETURN.getCode().equals(type)) {
//                        pushDistributorUserList = Collections.singletonList(refundData.getString(ReturnEnum.ORDERER_ID.getAttr()));
//                    } else if (ReturnTypeEnum.VALET_RETRUN.getCode().equals(type)) {
//                        // 代客下单消息推送
//                        pushDistributorUserList = pushHelper.getDistributorUserIdListByPushSetRule(corpid, refundData.getLongValue(ReturnEnum.LINK_DISTRIBUTOR.getAttr()));
//                    }
//                    PushRefTypePojo.Options options = new PushRefTypePojo.Options(refundEntity.getAppId(), refundEntity.getMenuId(), refundEntity.getFormId(), refundEntity.getDataId(), Collections.singletonList(refundEntity.getDataId()), SaasMarkEnum.SAAS.getCode(), businessTYpe, businessTYpe);
//                    // 订货单消息推送到经销商
//                    DistributorMessageRabbitMqDTO distributorMessageRabbitMqDTO = new DistributorMessageRabbitMqDTO(corpid, pushDistributorUserList, Collections.singletonList(refundEntity.getDataId()), 0, null, I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_ABANDONED_TITLE), String.format(I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_ABANDONED_CONTENT), refundEntity.getSerialNo()), null, options, DistributorMarkEnum.DISTRIBUTOR.getCode());
//                    baseProducer.sendMessage(PushTypeEnum.DISTRIBUTOR_REFUND_ABANDONED_PUSH, distributorMessageRabbitMqDTO);
//                } catch (Exception e) {
//                    LOG.error("退货单审核不通过消息推送", e);
//                }
//            };
//            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
//        }

        try {
            // 动态
            if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), returnDeleteBatchDTO.getDistributorMark())) {
                DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(returnDeleteBatchDTO.getBusinessType());
                FormDataDeleteBatchDTO formDataDeleteBatchDTO = BeanUtil.copyProperties(returnDeleteBatchDTO, FormDataDeleteBatchDTO.class, true);
                List<PaasFormDataEntityExt> allowDeletePaasFormDatas = new ArrayList<>(refundExtList.size());
                BeanUtil.copyPropertiesList(refundExtList, allowDeletePaasFormDatas, PaasFormDataEntityExt.class, true);
                dynamicStrategy.batchDelete(DynamicDeleteDTO.initDynamicDeleteDTO(formDataDeleteBatchDTO, refundExtList.stream().map(RefundEntityExt::getId).collect(Collectors.toList()), allowDeletePaasFormDatas));
            }
        } catch (Exception e) {
            LOG.error("退货退库动态删除失败", e);
        }

        //生成删除日志(区分单个删除和批量删除)
        String userId = returnDeleteBatchDTO.getUserId();
        String userName = returnDeleteBatchDTO.getLoginUserName();
        List<String> list = new ArrayList<>();
        Iterator<String> iterator = noAndName.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = noAndName.get(key);
            if(StringUtil.isEmpty(value)){
                list.add(key);
            } else {
                StringBuilder sb = new StringBuilder();
                sb.append(key).append("（").append(value).append("）");
                list.add(sb.toString());
            }
        }
        String nameStr = StringUtils.join(list, "，");
        if(deleteIdIn.size() > 1){
            String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_DELETE_FORM_DETAIL), userName, XbbRefTypeEnum.REFUND.getName(), deleteIdIn.size());
            List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            InfoArrPojo infoArrPojo = new InfoArrPojo();
            infoArrPojo.setTitle(RefundEnum.REFUND_NO.getAttrName());
            infoArrPojo.setContent(nameStr);
            infoArrPojoList.add(infoArrPojo);
            mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.REFUND, OperateTypeEnum.DELETE,
                    "", "", memo, returnDeleteBatchDTO.getHttpHeader());
        } else if (Objects.equals(deleteIdIn.size(), 1)){
            String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_DELETE_WORK), userName, XbbRefTypeEnum.REFUND.getName(), nameStr);
            mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.REFUND, OperateTypeEnum.DELETE,
                    deleteIdIn.get(0).toString(), nameStr, memo, returnDeleteBatchDTO.getHttpHeader());
        }

        return returnDeleteBatchVO;
    }

       @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        PaasFormDataEntityExt paasFormDataEntityExt = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt();
        String corpid = paasFormDataEntityExt.getCorpid();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContractField = new FieldAttrEntity();
        FieldAttrEntity returnAmountField = new FieldAttrEntity();
        FieldAttrEntity productField = new FieldAttrEntity();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), ReturnEnum.LINK_DISTRIBUTOR.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), ReturnEnum.ORDER_ID.getAttr())) {
                linkContractField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), ReturnEnum.RETURN_AMOUNT.getAttr())) {
                returnAmountField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), ReturnEnum.PRODUCTS.getAttr())) {
                productField = fieldAttrEntity;
            }
        }
        Integer businessType = handlerExplainInLinkItemDTO.getLinkBusinessType();
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(businessType);
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, CustomerManagementEnum.NAME.getAttr(), "");
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, customerName));
                break;
            case CONTRACT:
                String contractNo = paasFormDataEntityExt.getSerialNo();
                Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                map.put(ContractEnum.AMOUNT.getAttr(), FastJsonHelper.getDoubleOrDefaultFromFormData(linkFormData, ContractEnum.AMOUNT.getAttr(), 0D));
                map.put(StringConstant.FORM_ID, handlerExplainInLinkItemDTO.getSourceFormId());
                linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, contractNo, map));
                JSONArray linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, ContractEnum.LINK_CUSTOMER.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                //linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, paasFormDataEntityExt.getSerialNo()));


                JSONObject productData = new JSONObject();
                String linkAttr = refundServiceImpl.formmatRefundProduct4Show(linkDataId,corpid,productData);

                JSONArray productArray = formDataValidateProductHelp.otherProductToAnother(productData,productField,ReturnEnum.PRODUCTS.getAttr(),linkAttr,corpid, handlerExplainInLinkItemDTO.getLoginUser(), handlerExplainInLinkItemDTO.getBusinessType(), handlerExplainInLinkItemDTO.getLinkBusinessType());
                //productField.setDefaultAttr(saasUpdateHelp.setDefaultValue(productArray));
                Double totalAmount = 0D;
                if (!productArray.isEmpty()){
                    for (int i = 0;i < productArray.size();i++){
                        JSONObject jsonObject = productArray.getJSONObject(i);
                        Double num = jsonObject.getDouble(SelectProductEnum.NUM.getAttr());
                        Double price = jsonObject.getDouble(SelectProductEnum.PRICE.getAttr());
                        totalAmount += Arith.mul(num,price);
                    }
                }else {
                    Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(linkFormData, ContractEnum.AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
                    Double refundAmount = refundService.getRefundReturnAmount(corpid, linkDataId);
                    Double goodsAmount = Arith.sub(amount, refundAmount);
                    totalAmount = goodsAmount > 0 ? goodsAmount : BasicConstant.ZERO_DOUBLE;
                }
                DefaultAttrPoJo returnAmountPojo = returnAmountField.getDefaultAttr();
                returnAmountPojo.setUseLinkValue(BasicConstant.ONE);
                returnAmountPojo.setLinkFormValue(totalAmount);
                returnAmountField.setDefaultAttr(returnAmountPojo);
                break;
            default:
                break;
        }
    }

    @Override
    public ProductSummaryVO summaryProductList(BusinessProductListDTO businessProductListDTO) throws XbbException {
        ProductSummaryVO businessProductListVO = new ProductSummaryVO();
        Double num = 0D;
        Integer size = 0;

        String corpid = businessProductListDTO.getCorpid();
        Long refundId = businessProductListDTO.getDataId();
        RefundEntityExt refundEntityExt = refundModel.getByKey(refundId, corpid);
        if (refundEntityExt == null || Objects.equals(refundEntityExt.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
        }

        Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(refundEntityExt.getData(), RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);

        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("contractId", contractId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.COLUMNS, "product_num, price,business_num");
        List<ContractProductEntity> contractProductList = contractProductModel.findEntitys(modelMap);
        Double count = 0D;
        for (ContractProductEntity entity : contractProductList) {
            Double productNum = entity.getProductNum() != null ? Math.abs(entity.getProductNum()): 0D;
            Double price = entity.getPrice() == null ? 0D : entity.getPrice();
            count = Arith.add(count, Arith.mul(productNum, price));
            num = Arith.add(num, entity.getBusinessNum() == null ? productNum : entity.getBusinessNum());
        }
        size = contractProductList.size();

        String summaryInfo = String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_TYPE_NUM), size, Arith.doubleToBigDecimal(num));
        businessProductListVO.setSummaryInfo(summaryInfo);
        businessProductListVO.setMoneyInfo(String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_MONEY_COUNT), "", count));
        Boolean isJxcUse = paasAppService.validateAppEnable(null, XbbRefTypeEnum.JXC.getAlias(), SaasMarkEnum.SAAS.getCode(), corpid);
        if (isJxcUse) {
            // 添加关闭和开启退货退款的按钮
            JSONObject data = refundEntityExt.getData();
            // 退货单状态
            String returnStatus = FastJsonHelper.getStringOrDefaultFromFormData(data, ReturnEnum.ORDER_STATUS.getAttr(), ReturnStatusEnum.UNDER_REVIEW.getCode());
            // 只有退货单状态为处理中 且产品不为0的时候  展示关闭按钮
            if (Objects.equals(returnStatus, ReturnStatusEnum.PROCESSING.getCode()) && num != 0D) {
                ButtonPojo buttonPojo = new ButtonPojo();
                if (!Objects.equals(returnStatus, ReturnStatusEnum.CLOSED.getCode()) && businessProductListDTO.getLoginUser().getPermSet().contains(EnableButtonEnum.RETURN_UNABLE.getPermission())){
                    buttonPojo.setAttr("refund");
                    buttonPojo.setValue(OperateTypeEnum.UNABLE.getName());
                    buttonPojo.setLinkBusinessType(XbbRefTypeEnum.REFUND.getCode());
                    List<ButtonPojo> topRightButton = new ArrayList<>();
                    topRightButton.add(buttonPojo);
                    businessProductListVO.setTopRightButton(topRightButton);
                }
            }
        }
        return businessProductListVO;
    }

    @Override
    public void processTaskEnd(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) {
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        Long formId = processNodeTaskUpdateDTO.getFormId();
        Long taskId = processNodeTaskUpdateDTO.getProcessTaskId();

        PaasFormEntityExt formEntity = paasFormModel.getByKey(formId, corpid);
        if (BasicConstant.ONE.equals(formEntity.getDistributorMark())) {// 消息推送
            PaasProcessDataEntity paasProcessDataEntity = paasProcessDataModel.getByTaskId(taskId, corpid);
            // 退货单审核不通过消息推送
            JSONObject refundData = JSON.parseObject(paasProcessDataEntity.getData());
            Runnable runnable = () -> {
                Integer businessTYpe = XbbRefTypeEnum.RETURN.getCode();
                try {
                    String type = refundData.getString(ReturnEnum.REFUND_TYPE.getAttr());
                    List<String> pushDistributorUserList = new ArrayList<>();
                    if (ReturnTypeEnum.AUTONOMOUS_RETURN.getCode().equals(type)) {
                        pushDistributorUserList = Collections.singletonList(refundData.getString(ReturnEnum.ORDERER_ID.getAttr()));
                    } else if (ReturnTypeEnum.VALET_RETRUN.getCode().equals(type)) {
                        // 代客下单消息推送
                        pushDistributorUserList = pushHelper.getDistributorUserIdListByPushSetRule(corpid, refundData.getLongValue(ReturnEnum.LINK_DISTRIBUTOR.getAttr()));
                    }
                    PushRefTypePojo.Options options = new PushRefTypePojo.Options(paasProcessDataEntity.getAppId(), paasProcessDataEntity.getMenuId(), paasProcessDataEntity.getFormId(), 0L, Collections.singletonList(0L), SaasMarkEnum.SAAS.getCode(), businessTYpe, businessTYpe);
                    // 订货单消息推送到经销商
                    DistributorMessageRabbitMqDTO distributorMessageRabbitMqDTO = new DistributorMessageRabbitMqDTO(corpid, pushDistributorUserList, Collections.singletonList(0L), 0, null, I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_ABANDONED_TITLE), String.format(I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_ABANDONED_CONTENT), paasProcessDataEntity.getSerialNo()), null, options, DistributorMarkEnum.DISTRIBUTOR.getCode());
                    baseProducer.sendMessage(PushTypeEnum.DISTRIBUTOR_REFUND_ABANDONED_PUSH, distributorMessageRabbitMqDTO);
                } catch (Exception e) {
                    LOG.error("退货单审核不通过消息推送", e);
                }
            };
            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
        }
    }

    /**
     * @Author: wujian
     * @Description: 退货单关闭
     * @Date: 下午7:24 2021/2/2
     * @Param: [changeDocumentStatusSaveDTO]
     * @return: com.xbongbong.pro.detailtab.vo.ChangeDocumentStatusSaveVO
     **/
    @Override
    public ChangeDocumentStatusSaveVO changeDocumentStatus(ChangeDocumentStatusSaveDTO changeDocumentStatusSaveDTO) throws XbbException {
        ChangeDocumentStatusSaveVO changeDocumentStatusSaveVO = new ChangeDocumentStatusSaveVO();
        try {
            Boolean isOpen = changeDocumentStatusSaveDTO.getIsOpen();
            String corpid = changeDocumentStatusSaveDTO.getCorpid();
            Long refundId = changeDocumentStatusSaveDTO.getDataId();
            Integer businessType = changeDocumentStatusSaveDTO.getBusinessType();
            RefundEntityExt refundEntityExt = refundModel.getByKey(refundId, corpid);
            if (Objects.isNull(refundEntityExt)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            JSONObject returndata = refundEntityExt.getData();
            String returnStatus = FastJsonHelper.getStringOrDefaultFromFormData(returndata,ReturnEnum.ORDER_STATUS.getAttr(),ReturnStatusEnum.UNDER_REVIEW.getCode());
            if(!isOpen){
                returndata.put(ReturnEnum.ORDER_STATUS.getAttr(),ReturnStatusEnum.CLOSED.getCode());
                refundEntityExt.setData(returndata);
                refundModel.update(refundEntityExt);
            }
            //添加关闭和开启退货退款的按钮
            String refundStatus = FastJsonHelper.getStringOrDefaultFromFormData(returndata, RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());

            // 刷新页面saas关联新建工作流
            PaasFormDataEntityExt paasFormDataEntityExt = new PaasFormDataEntityExt();
            BeanUtil.copyProperties(refundEntityExt,paasFormDataEntityExt);
            if (Objects.equals(PlatFormEnum.DINGTALK.getValue(), changeDocumentStatusSaveDTO.getPlatform())) {
                // 设置移动端详情右上角操作
                FormDataGetVO formDataGetVO = new FormDataGetVO();
                mobileDetailService.handelMobileWorkFlow(changeDocumentStatusSaveDTO.getLoginUser(), XbbRefTypeEnum.transferBusinessType4Distributor(businessType,DistributorMarkEnum.DISTRIBUTOR.getCode()), formDataGetVO, paasFormDataEntityExt);
                changeDocumentStatusSaveVO.setTopPermissions(formDataGetVO.getTopPermissions());
            }else {
                List<WorkFlowPojo> workFlowPojoList = new ArrayList<>();
                proDetailHandlerHelp.handelDetailWorkFlow(XbbRefTypeEnum.transferBusinessType4Distributor(businessType,DistributorMarkEnum.DISTRIBUTOR.getCode()), paasFormDataEntityExt, workFlowPojoList, changeDocumentStatusSaveDTO.getLoginUser());
                changeDocumentStatusSaveVO.setWorkFlowPojoList(workFlowPojoList);
            }

            if (!isOpen) {
                Runnable runnable = () -> {
                    String type = returndata.getString(ReturnEnum.REFUND_TYPE.getAttr());
                    List<String> pushDistributorUserList = new ArrayList<>();
                    try {
                        if (ReturnTypeEnum.AUTONOMOUS_RETURN.getCode().equals(type)) {
                            Long createId = returndata.getLongValue(ReturnEnum.CREATOR_ID.getAttr());
                            pushDistributorUserList.add(createId.toString());
                        } else {
                            pushDistributorUserList = pushHelper.getDistributorUserIdListByPushSetRule(corpid, returndata.getLongValue(ReturnEnum.LINK_DISTRIBUTOR.getAttr()));
                        }
                        PushRefTypePojo.Options options = new PushRefTypePojo.Options(refundEntityExt.getAppId(), refundEntityExt.getMenuId(), refundEntityExt.getFormId(), refundId, Collections.singletonList(refundId), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.REFUND.getCode(), XbbRefTypeEnum.REFUND.getCode());
                        DistributorMessageRabbitMqDTO distributorMessageRabbitMqDTO = new DistributorMessageRabbitMqDTO(corpid, pushDistributorUserList, Collections.singletonList(refundId), 0, null, I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_CLOSE_TITLE), String.format(I18nMessageUtil.getMessage(DistributorOrderPushConstant.RETURN_ORDER_CLOSE_CONTENT), refundEntityExt.getSerialNo()), null, options, DistributorMarkEnum.DISTRIBUTOR.getCode());
                        baseProducer.sendMessage(PushTypeEnum.DISTRIBUTOR_REFUND_CLOSE_PUSH, distributorMessageRabbitMqDTO);
                    } catch (Exception e) {
                        LOG.error("退货单关闭消息推送", e);
                    }
                };
                threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
            }
        } catch (Exception e) {
            LOG.error("refundServiceImpl.changeDocumentStatus 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return changeDocumentStatusSaveVO;
    }



}
